import traceback
import sys
import parserbasic
import re
from codeparser import CodeObject

maxLineLength = 80

def pretty_print_item(name,obj,prefix=''):
	"""Returns a list of lines to print"""
	res = []
	subprefix = prefix+' '*(len(str(name))+2)
	if isinstance(obj,(tuple,list)) and len(str(obj))+len(subprefix) > maxLineLength:
		open,close = ('(',')') if isinstance(obj,tuple) else ('[',']')
		res.append(str(name)+'='+open)
		for i,vi in enumerate(obj):
			s = str(vi)
			if i!=0: s = subprefix + s
			if i+1<len(obj):
				s += ','
			else:
				s += close
			if i!=0:
				res.append(s)
			else:
				res[-1] += s
		return res
	else:
		return [str(name)+' = '+str(obj)]


def pretty_print_state(state,prefix=''):
	for (k,v) in state.iteritems():
		print prefix,
		for line in pretty_print_item(k,v,prefix):
			print line

def pretty_print_action(a,prefix=''):
	action = None
	params = None
	if isinstance(a,tuple):
		action,params = a
	else:
		action,params = a.action,a.params
	
	subprefix = prefix+(' '*(len(action.name)+2))
	#try to put as many params on one line as possible
	lines = []
	for i,(p,val) in enumerate(params.items()):
		lines += pretty_print_item(p,val)
		if i+1 < len(params):
			lines[-1] += ','
		else:
			lines[-1] += ')'
	if len(subprefix) + sum(len(l) for l in lines) < 80:
		print prefix+action.name+'('+''.join(lines)
	else:
		print prefix+action.name+'('+lines[0]
		for l in lines[1:]:
			print subprefix+l

def pretty_print_subplan_solution(soln,prefix=''):
	for s in soln:
		print prefix+str(s)

def pretty_print_solution_path(path,tab='  '):
	pretty_print_state(path[0].get_head().state)
	for e in path:
		pretty_print_action(e.a,tab)
		if e.get_plan():
					print tab+'Solution:'
					pretty_print_subplan_solution(e.get_plan().solution(),tab+tab)
		pretty_print_state(e.get_tail().state)

def dump_solution_path(path,fn):
    f = open(fn,'w')
    for id,e in enumerate(path):
        f.write(str(id+1)+"    "+str(e.get_head().state)+'\n')
    f.write(str(len(path)+1)+"    "+str(e.get_tail().state)+'\n')
    # now write edges
    f.write('#\n')
    for id,e in enumerate(path):
        status = "active"
        if e.failed(): status = "failed"
        if e.complete():
            if not e.get_plan() or e.get_plan().solution() == None:
                status = "complete"
            else:
                status = repr(e.get_plan().solution())
        f.write(str(id+1)+" "+str(id+2)+"    "+repr(e.a)+"; "+status+'\n')
    f.close()

class Outputter:
    def __init__(self):
        self.env = {}
        self.type = "all"
        self.start = None
        self.stop = None
        self.state = None
        self.actions = {}
    
    def output(self,path):
        if self.type == 'all':
            self.output_start()
            self.output_state(path[0].get_head().state,0)
            index = 0
            for e in path:
                self.output_action_edge(e,index)
                index += 1
                self.output_state(e.get_tail().state,index)
            self.output_stop()
        else:
            raise RuntimeError("TODO: step through path")

    def output_start(self):
        if self.start:
            print("Executing start")
            self.start.execute(self.env)

    def output_stop(self):
        if self.stop:
            self.stop.execute(self.env)

    def output_state(self,s,index=0):
        if self.state != None:
            print("Executing state "+str(index))
            localParams = s.copy()
            localParams['__index__']=index
            localParams['__state__']=s
            self.state.execute(self.env,localParams)
        else:
            pretty_print_state(s)

    def output_action_edge(self,e,index):
        subplan = None
        if e.get_plan():
            subplan = e.get_plan().solution()
        self.output_action(e.get_head().state,e.a,subplan,index)
    
    def output_action(self,state,a,subplan,index):
        if a.action.name in self.actions:
            localParams = state.copy()
            localParams.update(a.params)
            localParams['__index__']=index
            localParams['__state__']=state
            if subplan:
                localParams['__plan__']=subplan
            else:
                localParams['__plan__']=None
            self.actions[a.action.name].execute(self.env,localParams)
        else:
            pretty_print_action(a,'  ')
            if subplan:
                pretty_print_subplan_solution(subplan,'    ')
            

class OutputParser:
    def __init__(self,env):
        self.env = env
        
    def parse(self, code, start):
        outputter = Outputter()
        outputter.env = self.env.copy()
        linenos,sections = parserbasic.split_sections(code,['INIT:','STOP:','STATE:',re.compile('ACTION (.+):')],start+1)

        if 'INIT:' in linenos:
            code = sections['INIT:']
            outputter.start = CodeObject(code,'INIT',linenos['INIT:'][0])

        if 'STOP:' in linenos:
            code = sections['STOP:']
            outputter.stop = CodeObject(code,'STOP',linenos['STOP:'][0])
        
        if 'STATE:' in linenos:
            code = sections['STATE:']
            outputter.state = CodeObject(code,'STATE',linenos['STATE:'][0])

        for (k,v) in linenos.iteritems():
            if k.startswith('ACTION'):
                name = k[7:-1].strip()
                code = sections[k]
                outputter.actions[name] = CodeObject(code,'ACTION '+name,v[0])
        return outputter
